#include <malloc.h>
#include <strings.h>
#include <netinet/in.h>

#include "ft_proto.h"

/* 
 * compressed byte CRC
 * by me
 */
unsigned long ft_calc_checksum(char* pkt,int sz)
{
  unsigned int polynomial = 0xEDB88320;
  unsigned long shftReg = 0x0;
  int i;
  for (i = 0; i < sz; i++)
    shftReg += (polynomial >> ((i % 4)*8)) ^ (*(pkt+i));
  return shftReg;
}

/* generate the packet
 */
char* ft_gen_packet(struct ft_packet_t* pkt, int* size)
{
  int i = 0, j = 0;
  int static_size = ( sizeof(int)*3 + sizeof(long)*2 + pkt->length);
  int *buff = malloc(static_size+4);

  pkt->checksum = 0;
  //fill in the info with right endianess
  *(buff+0) = htonl(pkt->flags);
  *(buff+1) = htonl(pkt->seq_num);
  *(buff+2) = 0; 
  *(buff+3) = htonl(pkt->wstart);
  *(buff+4) = htonl(pkt->length);
  
  //fill in data
  if (pkt->length > 0 && pkt->data != NULL)
    for (i = PKT_HEADER_SIZE,j = 0; i < static_size; i++, j++)
      *(((char*)buff)+i) = *(pkt->data+j);

  //calculate the checksum
  pkt->checksum = ft_calc_checksum((char*)buff,static_size);
  *(buff+2) = htonl(pkt->checksum);

  //set the size returned
  *size = static_size;

  return (char*)buff;
}

/* unpack the buffer */
struct ft_packet_t* ft_unpack_packet(char* buff, int len)
{
  struct ft_packet_t* packet = malloc(sizeof(struct ft_packet_t));
  int* ibuff = (int*)buff;
  int i = 0;

  //read in fields
  packet->flags = ntohl(*ibuff);
  packet->seq_num = ntohl(*(ibuff+1));
  packet->checksum = ntohl(*(ibuff+2));
  packet->wstart = ntohl(*(ibuff+3));
  packet->length = ntohl(*(ibuff+4));

  //do some sanity checking and read in data
  if (packet->length > 0 && packet->length + PKT_HEADER_SIZE <= len)
  {
    packet->data = malloc(packet->length + 4);
    bzero(packet->data,packet->length);
  
    for (i = 0; i < packet->length && PKT_HEADER_SIZE+i < len; i++)
      *(packet->data+i) = *(buff+PKT_HEADER_SIZE+i);
  }
  else
    packet->length = 0;

  *(ibuff+2) = 0;

  //calculate checksum and verify
  if (ft_calc_checksum(buff,len) != packet->checksum)
    packet->flags = PKT_FCKSM;

  return packet;
}
